package libs.game.sokoban;

import libs.game.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *          This class can create sokoban game plans.
 *
 * @author  Jan Papousek
 * @version 2009-12-03
 */
public class SokobanGamePlanFactory {

    public static SokobanGamePlan changeBoxesAndTargets(SokobanGamePlan plan, Collection<Coordinates> changes) {
        if (plan == null) {
            throw new NullPointerException("Argument 'plan' is null.");
        }
        if (changes == null) {
            throw new NullPointerException("Argument 'changes' is null.");
        }
        Set<Coordinates> boxes = new HashSet<Coordinates>();
        List<Coordinates> targets = new ArrayList<Coordinates>();
        for (Coordinates change : changes) {
            if (plan.getField(change) == SokobanGamePlan.FIELD_BOX_ON_EMPTY
                    || plan.getField(change) == SokobanGamePlan.FIELD_BOX_ON_GOAL)
            {
                boxes.add(change);
            }
            else if (plan.getField(change) == SokobanGamePlan.FIELD_EMPTY
                        || plan.getField(change) == SokobanGamePlan.FIELD_GOAL)
            {
                targets.add(change);
            }
            else {
                throw new IllegalArgumentException("A target is wall or there is a person.");
            }
        }
        if (boxes.size() != targets.size()) {
            throw new IllegalArgumentException("Number of boxes is different from number of targets");
        }
        SokobanGamePlan changedPlan = new SokobanGamePlan(plan.getPlan());
        for (Coordinates box : boxes) {

            changedPlan.changeBox(box,targets.remove(0));
        }
        return changedPlan;
    }

    public static SokobanGamePlan createFromFile(String filename) throws IOException {
        BufferedReader reader = null;
        char[][] plan;
        try {
            reader = new BufferedReader(new FileReader(filename));
            String line = null;
            int maxLine = -1;
            List<List<Character>> lines = new ArrayList<List<Character>>();
            List<Character> lineChar = null;
            while ((line = reader.readLine()) != null) {
                lineChar = new ArrayList<Character>();
                int i = 0;
                for (i=0; (i < line.length()) && ((i <= maxLine) || (maxLine == -1)); i++) {
                    lineChar.add(new Character(line.charAt(i)));
                }
                if (maxLine == -1) {
                    maxLine = i;
                }
                else if (i != maxLine) {
                    throw new IOException("The source file has wrong format.");
                }
                lines.add(lineChar);
            }
            int rowNum = 0;
            int columnNum = 0;
            plan = new char[lines.size()][lines.get(0).size()];
            for (List<Character> row : lines) {
                for (Character item : row) {
                    switch(item) {
                        case SokobanGamePlan.FIELD_BOX_ON_EMPTY:
                        case SokobanGamePlan.FIELD_BOX_ON_GOAL:
                        case SokobanGamePlan.FIELD_EMPTY:
                        case SokobanGamePlan.FIELD_GOAL:
                        case SokobanGamePlan.FIELD_PERSON_ON_EMPTY:
                        case SokobanGamePlan.FIELD_PERSON_ON_GOAL:
                        case SokobanGamePlan.FIELD_WALL:
                            plan[rowNum][columnNum] = item;
                            break;
                        default:
                            throw new IOException("The source file has wrong format. There is uknown symbol '" + item + "'.");
                    }
                    columnNum++;
                }
                rowNum++;
                columnNum = 0;
            }
        }
        finally {
            if (reader != null) {
                reader.close();
            }
        }
        try {
            return new SokobanGamePlan(plan);
        }
        catch(IllegalArgumentException e) {
            throw new IOException("The source file has wrong format.",e);
        }
    }

}